/*
 * Copyright 2013 Agustina Martinez-Garcia

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
package uk.da.dext.genxml;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.apache.xmlbeans.XmlException;

import uk.da.dext.CategoryType;
import uk.da.dext.CodeType;
import uk.da.dext.DocumentType;
import uk.da.dext.MemoType;
import uk.da.dext.ObjectRelationType;
import uk.da.dext.QudexDocument;
import uk.da.dext.SourceType;

public class QudexXmlUpdateOperations {
	private Logger log = Logger.getLogger(QudexManagement.class);
	private QudexDocument qudexInstance;
	//private List<String> categoriesToRemove;
	private List<String> objectRelationsRemoved;

	public QudexXmlUpdateOperations(String xmlInstance) throws XmlException {
		this.qudexInstance = QudexDocument.Factory.parse(xmlInstance);
		//this.categoriesToRemove = new ArrayList<String>();
		this.objectRelationsRemoved = new ArrayList<String>();
		log.info("Qudex Instance parsed, QudexXmlUpdateOperations");
	}
	
	/*
	 * UPDATE AND DELETE OPERATIONS METHODS
	 * */
	/**
	 * 
	 * @param qudexPid
	 * @return
	 */
	public boolean deleteDocumentFromQudexInstance(String qudexPid) {
		DocumentType docType = this.getDocumentFromInstance(qudexPid);
		String documentId = docType.getId();
		if (docType != null) {
			int index = this.getDocumentIndexFromInstance(qudexPid);
			if (index != -1 ) {
				//Remove source
				this.deleteDocumentSources(docType.getResourceRef());
				this.qudexInstance.getQudex().getResourceCollection().getDocuments().removeDocument(index);
			}
			else {
				return false;
			}
		}
		//Delete relations
		this.deleteRelationshipsFromDocument(documentId);
		//Delete categories
		this.deleteCategoriesFromDocument(documentId);
		//DeleteObjects
		this.deleteObjectsFromDocument(documentId);
		return true;
	}

	/*
	 *Private auxiliary methods 
	 */
	private void deleteDocumentSources(String sourceRef) {
		int idx = 0;
		
		for (SourceType source : this.qudexInstance.getQudex().getResourceCollection().getSources().getSourceArray()) {
			if (source.getId().equals(sourceRef)) {
				this.qudexInstance.getQudex().getResourceCollection().getSources().removeSource(idx);
				break;
			} else idx++;
		}
	}
	/**
	 * 
	 * @param identifier
	 * @return
	 */
	private DocumentType getDocumentFromInstance(String identifier) {
		DocumentType[] docsArray = this.qudexInstance.getQudex().getResourceCollection().getDocuments().getDocumentArray();
		
		for (DocumentType doc : docsArray) {
			if (doc.getLabel().equalsIgnoreCase(identifier))
				return doc;
		}
		
		return null;
	}
	/**
	 * 
	 * @param identifier
	 * @return
	 */
	private int getDocumentIndexFromInstance(String identifier) {
		DocumentType[] docsArray = this.qudexInstance.getQudex().getResourceCollection().getDocuments().getDocumentArray();
		int counter = 0;
		for (DocumentType doc : docsArray) {
			if (doc.getLabel().equalsIgnoreCase(identifier))
				return counter;
			counter++;
		}
		
		return -1;
	}
	/**
	 * 
	 * @param documentId
	 */
	private void deleteCategoriesFromDocument(String documentId) {
		int indexDocumentRef = 0, indexCategory = 0;
		for (CategoryType cat : this.qudexInstance.getQudex().getCategoryCollection().getCategoryArray()) {
			for (String auxDocumentId : cat.getDocumentRefs()) {
				if (auxDocumentId.equals(documentId)) {
					cat.getDocumentRefs().remove(indexDocumentRef);
					//If the documentsArray for the given categories only contains the document
					//to remove then mark is as removable category
					if (cat.getDocumentRefs().size() == 1) {
						this.qudexInstance.getQudex().getCategoryCollection().removeCategory(indexCategory);
						//this.categoriesToRemove.add(cat.getId());
					}
					break;
				} else indexDocumentRef++;
			}
			indexCategory++;
		}
		//Remove the categories that only reference to a deleted document
		//this.callRecursiveDeleteCategories();
	}
	/**
	 * 
	 * @param documentId
	 */
	private void deleteRelationshipsFromDocument(String documentId) {
		int indexRelation = 0;
		//All relationships from Document to any other object and from any object to a given document
		for (ObjectRelationType auxRelation : this.qudexInstance.getQudex().getRelationCollection().getObjectRelationArray()) {
			if (auxRelation.getObjectSource().equals(documentId)) {
				this.objectRelationsRemoved.add(auxRelation.getObjectTarget());
				this.qudexInstance.getQudex().getRelationCollection().removeObjectRelation(indexRelation);		
			} else if (auxRelation.getObjectTarget().equals(documentId)) {
				this.objectRelationsRemoved.add(auxRelation.getObjectSource());
				this.qudexInstance.getQudex().getRelationCollection().removeObjectRelation(indexRelation);
			} else indexRelation++;
		}
	}
	/**
	 * 
	 */
	@SuppressWarnings("unused")
	private void callRecursiveDeleteCategories() {
		int idx = 0;
		for (CategoryType cat: this.qudexInstance.getQudex().getCategoryCollection().getCategoryArray()) {
			recursiveDeleteCategories(cat, idx);
			idx++;
		}
	}
	/**
	 * 
	 * @param category
	 * @param idx
	 */
	private void recursiveDeleteCategories(CategoryType category, int idx) {
		if (category.getId().equals(category)) {
			if (category.getCategoryRefs().size() != 0) {
				for (String catId: category.getCategoryRefs()) {
					CategoryType auxCat = this.getCategoryFromCollection(catId);
					if (auxCat != null) {
						category.getCategoryRefs().remove(catId);
						recursiveDeleteCategories(auxCat, idx);
					} else continue;
				}
			} else {
				if (category.getDocumentRefs().size() == 0)
					this.qudexInstance.getQudex().getCategoryCollection().removeCategory(idx);
			}
		}
	}
	/**
	 * 
	 * @param catId
	 * @return
	 */
	private CategoryType getCategoryFromCollection(String catId) {
		for (CategoryType cat : this.qudexInstance.getQudex().getCategoryCollection().getCategoryArray()) {
			if (cat.getId().equals(catId))
				return cat;
		}
		return null;
	}
	/**
	 * 
	 * @param documentId
	 */
	private void deleteObjectsFromDocument(String documentId) {
		int idx = 0;
		for (String objectId : this.objectRelationsRemoved) {
			//Check memos			
			for (MemoType memo : this.qudexInstance.getQudex().getMemoCollection().getMemoArray()) {
				if (memo.getId().equals(objectId)) {
					this.qudexInstance.getQudex().getMemoCollection().removeMemo(idx);
					break;
				} else idx++;
			}
			idx = 0;
			//Check codes
			for (CodeType code : this.qudexInstance.getQudex().getCodeCollection().getCodeArray()) {
				if (code.getId().equals(objectId)) {
					this.qudexInstance.getQudex().getCodeCollection().removeCode(idx);
					break;
				} else idx++;
			}
		}
		
	}
}
